package com.randi.monitor.service.impl;

import com.randi.common.constant.CacheConstants;
import com.randi.common.utils.RedisUtil;
import com.randi.common.utils.StringUtils;
import com.randi.monitor.dto.SysCache;
import com.randi.monitor.service.ISysCacheService;
import com.randi.monitor.vo.CacheInfo;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public class SysCacheServiceImpl implements ISysCacheService {

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 通配符
     */
    private final static String WILDCARD = "*";

    /**
     * 缓存集合
     */
    private final static List<SysCache> caches = new ArrayList<>();

    static {
        caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_ACCESS_KEY, "登录用户信息"));
//        caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_REFRESH_KEY, "登录续期信息"));
        caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码"));
//        caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "参数配置"));
        caches.add(new SysCache(CacheConstants.FILE_DOWNLOAD_KEY, "文件下载"));
//        caches.add(new SysCache(CacheConstants.EXPORT_TASK_KEY, "导出任务"));
        caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重复提交"));
        caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流策略"));
        caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数"));
        caches.add(new SysCache(CacheConstants.PWD_EDIT_ERR_CNT_KEY, "密码修改错误次数"));

        // 数据缓存
        caches.add(new SysCache(CacheConstants.SYS_USER, "用户信息"));
        caches.add(new SysCache(CacheConstants.SYS_USER_ROLE, "用户角色信息"));
        caches.add(new SysCache(CacheConstants.SYS_ROLE, "角色信息"));
        caches.add(new SysCache(CacheConstants.SYS_ROLE_MENU, "角色菜单信息"));
        caches.add(new SysCache(CacheConstants.SYS_MENU, "菜单信息"));
        caches.add(new SysCache(CacheConstants.SYS_NOTICE, "公告信息"));
        caches.add(new SysCache(CacheConstants.SYS_DICT, "字典信息"));
        caches.add(new SysCache(CacheConstants.SYS_DICT_DATA, "字典数据"));
        caches.add(new SysCache(CacheConstants.SYS_LOG_LOGIN, "登录日志信息"));
        caches.add(new SysCache(CacheConstants.SYS_LOG_OPERATE, "操作日志信息"));
    }

    /**
     * 获取缓存监控信息
     *
     * @return 缓存监控信息
     */
    @Override
    public CacheInfo getCacheInfo() {
        CacheInfo cacheInfo = new CacheInfo();
        Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::info);
        Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
        Object dbSize = redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::dbSize);

        List<Map<String, String>> pieList = new ArrayList<>();
        if(commandStats != null){
            commandStats.stringPropertyNames().forEach(key -> {
                Map<String, String> data = new HashMap<>(2);
                String property = commandStats.getProperty(key);
                data.put("name", StringUtils.removeStart(key, "cmdstat_"));
                data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
                pieList.add(data);
            });
        }

        cacheInfo.setInfo(info);
        cacheInfo.setDbSize(dbSize);
        cacheInfo.setCommand(pieList);
        return cacheInfo;
    }

    /**
     * 获取缓存名称列表
     *
     * @return 缓存名称列表
     */
    @Override
    public List<SysCache> getCacheNames() {
        return caches.stream()
                .sorted(Comparator.comparing(SysCache::getCacheName))
                .collect(Collectors.toList());
    }

    /**
     * 获取缓存键列表
     *
     * @param sysCache 缓存信息
     * @return 缓存键列表
     */
    @Override
    public List<SysCache> getCacheKeys(SysCache sysCache) {
        String cacheName = sysCache.getCacheName();

        String match = cacheName.endsWith(":")? cacheName : cacheName + ":";
        Set<String> cacheKeys = redisUtil.getCacheKeys(match + WILDCARD);

        if (cacheKeys.isEmpty()) {
            return Collections.emptyList();
        }

        String cacheKey = sysCache.getCacheKey();

        return cacheKeys.stream()
                .sorted(Comparator.comparing(String::toString))
                .map(key -> {
                    SysCache cache = new SysCache();
                    cache.setCacheName(cacheName);
                    cache.setCacheKey(key);
                    cache.setExpire(redisUtil.getExpire(key));
                    return cache;
                })
                .filter(c -> StringUtils.isEmpty(cacheKey) || c.getCacheKey().contains(cacheKey))
                .collect(Collectors.toList());
    }

    /**
     * 获取缓存值
     *
     * @param cacheKey 缓存键名
     * @return 缓存键值
     */
    @Override
    public SysCache getCache(String cacheKey) {
        SysCache cache = new SysCache();
        Object cacheValue = redisUtil.getCache(cacheKey);
        if (cacheValue != null) {
            cache.setCacheKey(cacheKey);
            cache.setCacheValue(cacheValue);
            cache.setExpire(redisUtil.getExpire(cacheKey));
        }
        return cache;
    }

    /**
     * 清空缓存
     *
     * @param cacheName 缓存名称
     */
    @Override
    public void clearCacheName(String cacheName) {
        Set<String> cacheKeys = redisUtil.getCacheKeys(cacheName + "*");
        redisUtil.delete(cacheKeys.toArray(new String[0]));
    }

    /**
     * 清空缓存
     *
     * @param cacheKey 缓存键名
     */
    @Override
    public void clearCacheKey(String cacheKey) {
        redisUtil.delete(cacheKey);
    }


}
